//备注：拷贝代码请加上作者信息
//作者：王海涛
//邮箱：1126471088@qq.com
//版本：V1.0.0
#include "exti_bsp.h"
#include "gd32f4xx_misc.h"
#include "gd32f4xx_syscfg.h"

/*EXTI总管理结构体*/
static struct
{
	volatile unsigned int exti_line_mutex;       //外部中断线互斥锁
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin0;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin1;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin2;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin3;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin4;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin5;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin6;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin7;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin8;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin9;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin10;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin11;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin12;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin13;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin14;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Pin15;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_PVD;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_RTC_Alarm;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_USB_FS_Wakeup;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_Ethernet_Wakeup;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_USB_HS_Wakeup;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_RTC_Time;
	WHT_EXTI_BSP_Interrupt_Callback_t IT_CB_RTC_Wakeup;
}EXTI_Data;


/*EXTI中断优先级配置*/
static void EXTI_NVIC_Config(unsigned char NVIC_IRQChannel)
{
	NVIC_SetPriority((IRQn_Type)NVIC_IRQChannel, 15);
	NVIC_EnableIRQ((IRQn_Type)NVIC_IRQChannel);
}
/*EXTI GPIO中断的GPIO初始化*/
static void WHT_EXTI_BSP_GPIO_Init(const WHT_EXTI_Config_t* config)
{
	WHT_GPIO_BSP.WHT_Set_Clock(config->Portx, ENABLE);
	WHT_GPIO_BSP.WHT_Set_Pin(config->Portx, config->Pinx, Hig);
	WHT_GPIO_BSP.WHT_Set_Mode(config->Portx, config->Pinx, Mode_In_FLOATING);
}

/*EXTI线路使能或失能*/
static void WHT_EXTI_BSP_Line_Cmd(const WHT_EXTI_Config_t* config, ControlStatus state)
{
	//开启中断或事件
	if (config->Mode == Mode_Interrupt)
	{
		if (state == ENABLE)
		{
			exti_interrupt_enable((exti_line_enum)config->Line);
		}
		else
		{
			exti_interrupt_disable((exti_line_enum)config->Line);
		}
	}
	else
	{
		if (state == ENABLE)
		{
			exti_event_enable((exti_line_enum)config->Line);
		}
		else
		{
			exti_event_disable((exti_line_enum)config->Line);
		}
	}
	exti_flag_clear((exti_line_enum)config->Line);
	exti_init((exti_line_enum)config->Line, (exti_mode_enum)config->Mode, (exti_trig_type_enum)config->Trigger);
}
/*EXTI配置*/
static void WHT_EXTI_BSP_Config(const WHT_EXTI_Config_t* config)
{
	WHT_EXTI_BSP_Interrupt_Callback_t* Interrupt_Callback;
	unsigned char NVIC_IRQChannel;

	switch (config->Line)
	{
	case Exti_Line_Pin0:  NVIC_IRQChannel = EXTI0_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin0; break;
	case Exti_Line_Pin1:  NVIC_IRQChannel = EXTI1_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin1; break;
	case Exti_Line_Pin2:  NVIC_IRQChannel = EXTI2_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin2; break;
	case Exti_Line_Pin3:  NVIC_IRQChannel = EXTI3_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin3; break;
	case Exti_Line_Pin4:  NVIC_IRQChannel = EXTI4_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin4; break;
	case Exti_Line_Pin5:  NVIC_IRQChannel = EXTI5_9_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin5; break;
	case Exti_Line_Pin6:  NVIC_IRQChannel = EXTI5_9_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin6; break;
	case Exti_Line_Pin7:  NVIC_IRQChannel = EXTI5_9_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin7; break;
	case Exti_Line_Pin8:  NVIC_IRQChannel = EXTI5_9_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin8; break;
	case Exti_Line_Pin9:  NVIC_IRQChannel = EXTI5_9_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin9; break;
	case Exti_Line_Pin10: NVIC_IRQChannel = EXTI10_15_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin10; break;
	case Exti_Line_Pin11: NVIC_IRQChannel = EXTI10_15_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin11; break;
	case Exti_Line_Pin12: NVIC_IRQChannel = EXTI10_15_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin12; break;
	case Exti_Line_Pin13: NVIC_IRQChannel = EXTI10_15_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin13; break;
	case Exti_Line_Pin14: NVIC_IRQChannel = EXTI10_15_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin14; break;
	case Exti_Line_Pin15: NVIC_IRQChannel = EXTI10_15_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_Pin15; break;
	case Exti_Line_LVD:   NVIC_IRQChannel = LVD_IRQn;       Interrupt_Callback = &EXTI_Data.IT_CB_PVD; break;
	case Exti_Line_RTC_Alarm: NVIC_IRQChannel = RTC_Alarm_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_RTC_Alarm; break;
	case Exti_Line_USB_FS:    NVIC_IRQChannel = USBFS_WKUP_IRQn;Interrupt_Callback = &EXTI_Data.IT_CB_USB_FS_Wakeup; break;
#if defined(GD32F450) || defined(GD32F470) || defined(GD32F407) || defined(GD32F427)
	case Exti_Line_Ethernet:  NVIC_IRQChannel = ENET_WKUP_IRQn;   Interrupt_Callback = &EXTI_Data.IT_CB_Ethernet_Wakeup; break;
#endif
#if defined(GD32F450) || defined(GD32F470) || defined(GD32F405) || defined(GD32F425) || defined(GD32F407) || defined(GD32F427)
	case Exti_Line_USB_HS:	  NVIC_IRQChannel = USBHS_WKUP_IRQn;Interrupt_Callback = &EXTI_Data.IT_CB_USB_HS_Wakeup; break;
#endif
	case Exti_Line_RTC_Time:  NVIC_IRQChannel = TAMPER_STAMP_IRQn; Interrupt_Callback = &EXTI_Data.IT_CB_RTC_Time; break;
	case Exti_Line_RTC_Wakeup:NVIC_IRQChannel = RTC_WKUP_IRQn;   Interrupt_Callback = &EXTI_Data.IT_CB_RTC_Wakeup; break;
	default:
		return;
	}
	if (config->Type == Exti_GPIO)
	{
		WHT_EXTI_BSP_GPIO_Init(config);
		/* 使能 SYSCFG 时钟 ，使用GPIO外部中断时必须使能SYSCFG时钟*/
		rcu_periph_clock_enable(RCU_SYSCFG);
		/* 连接 EXTI 中断源 */
		//示例 syscfg_exti_line_config(EXTI_SOURCE_GPIOA, EXTI_SOURCE_PIN0);
		syscfg_exti_line_config((config->Portx - PortA) / (PortB - PortA), 31 - __clz(config->Pinx));
	}
	*Interrupt_Callback = NULL;
	if (config->Mode == Mode_Interrupt)
	{
		EXTI_NVIC_Config(NVIC_IRQChannel);
		*Interrupt_Callback = config->Interrupt_Callback;
	}
	WHT_EXTI_BSP_Line_Cmd(config, ENABLE);
}
/*EXTI手动触发中断或关闭中断*/
static void WHT_EXTI_BSP_Soft_Interrupt(const WHT_EXTI_Config_t* config, ControlStatus state)
{
	if (state == DISABLE)
		exti_interrupt_flag_clear((exti_line_enum)config->Line);
	else
		exti_software_interrupt_enable((exti_line_enum)config->Line);
}
/*EXTI获取线路锁*/
static FlagStatus WHT_EXTI_BSP_Get_Line_Mutex_State(const WHT_EXTI_Config_t* config)
{
	return (EXTI_Data.exti_line_mutex & config->Line) == config->Line ? SET : RESET;
}
/*EXTI清除线路锁*/
static void WHT_EXTI_BSP_Clr_Line_Mutex_State(const WHT_EXTI_Config_t* config)
{
	EXTI_Data.exti_line_mutex &= ~config->Line;
}

/*EXTI注册*/
static ErrStatus WHT_EXTI_BSP_Register(const WHT_EXTI_Config_t* config)
{
	if ((EXTI_Data.exti_line_mutex & config->Line) == config->Line)//此线路已经被注册上了
		return ERROR;
	EXTI_Data.exti_line_mutex |= config->Line;//注册到此线路
	return SUCCESS;
}

const WHT_EXTI_BSP_t WHT_EXTI_BSP =
{
	.WHT_Register = WHT_EXTI_BSP_Register,
	.WHT_Config = WHT_EXTI_BSP_Config,
	.WHT_Line_Cmd = WHT_EXTI_BSP_Line_Cmd,
	.WHT_Soft_Interrupt = WHT_EXTI_BSP_Soft_Interrupt,
	.WHT_Get_Line_Mutex_State = WHT_EXTI_BSP_Get_Line_Mutex_State,
	.WHT_Clr_Line_Mutex_State = WHT_EXTI_BSP_Clr_Line_Mutex_State,
};



/*EXTI0中断服务程序*/
void EXTI0_IRQHandler(void)
{
	if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin0) == SET)
	{
		if (EXTI_Data.IT_CB_Pin0 != NULL)
			EXTI_Data.IT_CB_Pin0();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin0);
	}
}
/*EXTI1中断服务程序*/
void EXTI1_IRQHandler(void)
{
	if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin1) == SET)
	{
		if (EXTI_Data.IT_CB_Pin1 != NULL)
			EXTI_Data.IT_CB_Pin1();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin1);
	}
}
/*EXTI2中断服务程序*/
void EXTI2_IRQHandler(void)
{
	if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin2) == SET)
	{
		if (EXTI_Data.IT_CB_Pin2 != NULL)
			EXTI_Data.IT_CB_Pin2();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin2);
	}
}
/*EXTI3中断服务程序*/
void EXTI3_IRQHandler(void)
{
	if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin3) == SET)
	{
		if (EXTI_Data.IT_CB_Pin3 != NULL)
			EXTI_Data.IT_CB_Pin3();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin3);
	}
}
/*EXTI4中断服务程序*/
void EXTI4_IRQHandler(void)
{
	if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin4) == SET)
	{
		if (EXTI_Data.IT_CB_Pin4 != NULL)
			EXTI_Data.IT_CB_Pin4();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin4);
	}
}
/*EXTI5 6 7 8 9中断服务程序*/
void EXTI5_9_IRQHandler(void)
{
	if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin5) == SET)
	{
		if (EXTI_Data.IT_CB_Pin5 != NULL)
			EXTI_Data.IT_CB_Pin5();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin5);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin6) == SET)
	{
		if (EXTI_Data.IT_CB_Pin6 != NULL)
			EXTI_Data.IT_CB_Pin6();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin6);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin7) == SET)
	{
		if (EXTI_Data.IT_CB_Pin7 != NULL)
			EXTI_Data.IT_CB_Pin7();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin7);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin8) == SET)
	{
		if (EXTI_Data.IT_CB_Pin8 != NULL)
			EXTI_Data.IT_CB_Pin8();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin8);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin9) == SET)
	{
		if (EXTI_Data.IT_CB_Pin9 != NULL)
			EXTI_Data.IT_CB_Pin9();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin9);
	}
}
/*EXTI10 11 12 13 14 15中断服务程序*/
void EXTI10_15_IRQHandler(void)
{
	if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin10) == SET)
	{
		if (EXTI_Data.IT_CB_Pin10 != NULL)
			EXTI_Data.IT_CB_Pin10();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin10);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin11) == SET)
	{
		if (EXTI_Data.IT_CB_Pin11 != NULL)
			EXTI_Data.IT_CB_Pin11();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin11);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin12) == SET)
	{
		if (EXTI_Data.IT_CB_Pin12 != NULL)
			EXTI_Data.IT_CB_Pin12();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin12);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin13) == SET)
	{
		if (EXTI_Data.IT_CB_Pin13 != NULL)
			EXTI_Data.IT_CB_Pin13();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin13);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin14) == SET)
	{
		if (EXTI_Data.IT_CB_Pin14 != NULL)
			EXTI_Data.IT_CB_Pin14();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin14);
	}
	else if (exti_interrupt_flag_get((exti_line_enum)Exti_Line_Pin15) == SET)
	{
		if (EXTI_Data.IT_CB_Pin15 != NULL)
			EXTI_Data.IT_CB_Pin15();
		exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Pin15);
	}
}
/*电源管理中断服务程序*/
void LVD_IRQHandler(void)
{
	if (EXTI_Data.IT_CB_PVD != NULL)
		EXTI_Data.IT_CB_PVD();
	exti_interrupt_flag_clear((exti_line_enum)Exti_Line_LVD);
}
/*RTC闹钟事件中断服务程序 */
void RTC_Alarm_IRQHandler(void)
{
	if (EXTI_Data.IT_CB_RTC_Alarm != NULL)
		EXTI_Data.IT_CB_RTC_Alarm();
	exti_interrupt_flag_clear((exti_line_enum)Exti_Line_RTC_Alarm);
}
/*USB FS唤醒中断服务程序*/
void USBFS_WKUP_IRQHandler(void)
{
	if (EXTI_Data.IT_CB_USB_FS_Wakeup != NULL)
		EXTI_Data.IT_CB_USB_FS_Wakeup();
	exti_interrupt_flag_clear((exti_line_enum)Exti_Line_USB_FS);
}
/*以太网唤醒中断服务程序*/
void ENET_WKUP_IRQHandler(void)
{
	if (EXTI_Data.IT_CB_Ethernet_Wakeup != NULL)
		EXTI_Data.IT_CB_Ethernet_Wakeup();
	exti_interrupt_flag_clear((exti_line_enum)Exti_Line_Ethernet);
}
/*USB HS唤醒中断服务程序*/
void USBHS_WKUP_IRQHandler(void)
{
	if (EXTI_Data.IT_CB_USB_HS_Wakeup != NULL)
		EXTI_Data.IT_CB_USB_HS_Wakeup();
	exti_interrupt_flag_clear((exti_line_enum)Exti_Line_USB_HS);
}
/*RTC入侵中断服务程序*/
void TAMPER_STAMP_IRQHandler(void)
{
	if (EXTI_Data.IT_CB_RTC_Time != NULL)
		EXTI_Data.IT_CB_RTC_Time();
	exti_interrupt_flag_clear((exti_line_enum)Exti_Line_RTC_Time);
}
/*RTC唤醒中断服务程序*/
void RTC_WKUP_IRQHandler(void)
{
	if (EXTI_Data.IT_CB_RTC_Wakeup != NULL)
		EXTI_Data.IT_CB_RTC_Wakeup();
	exti_interrupt_flag_clear((exti_line_enum)Exti_Line_RTC_Wakeup);
}
